package fr.asip.cps3.exemple.modele.jni;

import fr.asip.cps3.exemple.modele.Application;
import iaik.pkcs.pkcs11.wrapper.PKCS11Exception;

import java.io.IOException;

import org.apache.log4j.Logger;

public class TraitementsSpecifiquesImplementation implements TraitementsSpecifiques {

	/**
	 * Le loggeur
	 */
	private static Logger log = Logger.getLogger(TraitementsSpecifiquesImplementation.class);	
	
	/**
	 * Niveau de log Debug
	 */
	private static final int LOG_DEBUG = 1;
	 
	/**
	 * Niveau de log Info
	 */
	private static final int LOG_INFO = 2;
	 
	/**
	 * Niveau de log Warn 
	 */
	private static final int LOG_WARN = 3;
	
	/**
	 * Niveau de log Error
	 */
	private static final int LOG_ERROR = 4;
	
	/**
	 * Indication si la librairie JNI est bien chargee
	 */
	protected static boolean estChargee = false;	
	
	/**
	 * La librairie à utiliser
	 */
	private String librairiePKCS11;

	/**
	 * La librairie à utiliser
	 */
	private char[] codePorteur;	
	
	/**
	 * L'application
	 */
	private Application application;
	
	/**
	 * Cette methode charge la librairie native et est appelée exactement une fois pour cette classe
	 */
	protected static synchronized void chargeLibrairieJNI(String librairieTS) {
		
		if (!estChargee) {
			  System.loadLibrary(librairieTS);
			  estChargee = true;
		}		
		
	}

	/**
	 * Se connecte au driver PKCS#11 donné
	 *
	 * @param librairiePKCS11 La librairie PKCS#11
	 * @param librairieTS La librairie Traitements spécifiques à utiliser
	 * @throws IOException
	 */
	TraitementsSpecifiquesImplementation(Application application, String librairieTS, String librairiePKCS11) throws IOException {
		chargeLibrairieJNI(librairieTS);
		connecte(librairiePKCS11);
		this.application = application;
		this.librairiePKCS11 = librairiePKCS11;
	}

	/**
	 * Connecte cet objet à la librairie PKCS#11 spécifiée.
	 * @param librairiePKCS11 La librairie PKCS#11
	 * @throws IOException
	 */
	protected synchronized native void connecte(String librairiePKCS11) throws IOException;

	/**
	 * Initialise la librairie PKCS#11 spécifiée.
	 * @param librairiePKCS11 La librairie PKCS#11
	 * @throws PKCS11Exception
	 */
	public synchronized native void initialiseLibrairie() throws PKCS11Exception;	
	
	/*
	 * (non-Javadoc)
	 * @see fr.asip.cps3.exemple.modele.jni.TraitementsSpecifiques#etatConnexionCarte()
	 */
	public native void etatConnexionCarte() throws PKCS11Exception;	
	
	/*
	 * (non-Javadoc)
	 * @see fr.asip.cps3.exemple.modele.jni.TraitementsSpecifiques#assistantAuthentification()
	 */
	public native void assistantAuthentification() throws PKCS11Exception;	

	/*
	 * (non-Javadoc)
	 * @see fr.asip.cps3.exemple.modele.jni.TraitementsSpecifiques#etatSaisieCodePorteur()
	 */
	public native void etatSaisieCodePorteur() throws PKCS11Exception;
	
	/*
	 * (non-Javadoc)
	 * @see fr.asip.cps3.exemple.modele.jni.TraitementsSpecifiques#recyclageCodePorteur()
	 */
	public native void recyclageCodePorteur() throws PKCS11Exception;		

	/*
	 * (non-Javadoc)
	 * @see fr.asip.cps3.exemple.modele.jni.TraitementsSpecifiques#authentificationApresRetraitCarte()
	 */
	public native void authentificationApresRetraitCarte() throws PKCS11Exception;	

	/*
	 * (non-Javadoc)
	 * @see fr.asip.cps3.exemple.modele.jni.TraitementsSpecifiques#authentificationApresRetraitLecteur()
	 */
	public native void authentificationApresRetraitLecteur() throws PKCS11Exception;	
	
	/*
	 * (non-Javadoc)
	 * @see fr.asip.cps3.exemple.modele.jni.TraitementsSpecifiques#lectureObjetDonneesApplicatives()
	 */
	public native byte[] lectureObjetDonneesApplicatives() throws PKCS11Exception;		

	/*
	 * (non-Javadoc)
	 * @see fr.asip.cps3.exemple.modele.jni.TraitementsSpecifiques#modificationObjetDonneesApplicatives()
	 */
	public native byte[] modificationObjetDonneesApplicatives() throws PKCS11Exception;	
	
	
	/**
	 * Méthode permettant de logger et invoqué depuis la couche C
	 * @param message Message à logger
	 */
	public void log(int niveau, String message){
		
		switch (niveau) {
		
			case LOG_DEBUG:
			default:
				log.debug(message);				
				break;
	
			case LOG_INFO:
				log.info(message);
				break;
				
			case LOG_WARN:
				log.warn(message);
				break;
				
			case LOG_ERROR:
				log.error(message);
				break;
				
		}
	}

	/**
	 * Demande de connexion d'un lecteur à l'utilisateur
	 */
	public int demandeConnexionLecteur(){
		
		if(application != null)
			return application.declencheDemandeConnexionLecteur();
		return 0;
		
	}

	/**
	 * Demande d'insertion d'une carte supportee à l'utilisateur
	 */
	public int demandeInsertionCarte(){
		
		if(application != null)
			return application.declencheDemandeInsertionCarte();
		return 0;
		
	}
	
	/**
	 * Demande de choix du nombre d'essais possibles avant blocage du code porteur
	 * 
	 * @return Réponse utilisateur
	 */
	public int demandeChoixNbEssaisPossiblesAvantBlocageCodePorteur(){
		
		if(application != null)
			return application.declencheDemandeChoixNbEssaisPossiblesAvantBlocageCodePorteur();
		return 0;
		
	}	

	/**
	 * Demande de saisie du code porteur à l'utilisateur
	 * 
	 * @param nbEssais Flag permettant de déterminer le message à afficher concernant le nombre d'essai
	 * @param conformiteCodePorteur Etat de conformité du code porteur
	 * @param numeroSerieCarte Numéro de série de la carte
	 * @return Tableau de 2 éléments, contenant le choix utilisateur [0] et le code porteur saisi [1]
	 */
	public Object[] demandeSaisieCodePorteur(long nbEssais, long conformiteCodePorteur, char numeroSerieCarte[]){
		
		if(application != null)
			return application.declencheDemandeSaisieCodePorteur(nbEssais, conformiteCodePorteur, (numeroSerieCarte != null)?(new String(numeroSerieCarte)).trim():null);
		return null;
		
	}

	/**
	 * Demande de recyclage du code porteur à l'utilisateur
	 * 
	 * @param nbEssais Flag permettant de déterminer le message à afficher concernant le nombre d'essai
	 * @param conformiteCodeDeblocage Etat de conformité du code de déblocage
	 * @param conformiteCodePorteur Etat de conformité du code porteur
	 * @param numeroSerieCarte Numéro de série de la carte
	 * @return Tableau de 4 éléments, contenant le choix utilisateur [0] et le code de déblocage [1], le 1er code porteur saisi [2] et le 2eme code porteur saisi [3]
	 */
	public Object[] demandeRecyclageCodePorteur(long nbEssais, long conformiteCodeDeblocage, long conformiteCodePorteur, char numeroSerieCarte[]){
		
		if(application != null)
			return application.declencheDemandeRecyclageCodePorteur(nbEssais, conformiteCodeDeblocage, conformiteCodePorteur, (numeroSerieCarte != null)?(new String(numeroSerieCarte)).trim():null);
		return null;
		
	}	

	/**
	 * Demande d'action lecteur (retrait/connexion) ou carte (retrait/insertion)
	 * 
	 * @param typeAction Le type d'action à demander
	 * @param numeroSerieCarte Numéro de série de la carte
	 * @return Réponse utilisateur
	 */
	public int demandeActionLecteurCarte(int typeAction, char numeroSerieCarte[]){
		
		if(application != null)
			return application.declencheDemandeActionLecteurCarte(typeAction, (numeroSerieCarte != null)?(new String(numeroSerieCarte)).trim():null);
		return 0;
		
	}	
	
	/**
	 * Déclenche l'alerte de carte retrouvée
	 * 
	 */
	public void alerteCarteRetrouvee(){
		
		if(application != null)
			application.declencheAlerteCarteRetrouvee();
		
	}	
	
	/**
	 * Demande de modification d'un objet de données applicatives
	 * 
	 * @param valeur Valeur à modifier
	 * @return Tableau de 2 éléments, contenant le choix utilisateur [0] et le valeur de l'attribut modifiée [1]
	 */
	public Object[] demandeModificationObjetDonneesApplicatives(byte[] valeur){
		
		if(application != null)
			return application.declencheDemandeModificationObjetDonneesApplicatives(valeur);
		return null;
		
	}	
	
	/*
	 * (non-Javadoc)
	 * @see fr.asip.cps3.exemple.modele.jni.TraitementsSpecifiques#estLibrairieDefinie()
	 */
	public boolean estLibrairieDefinie() {
		return (librairiePKCS11 != null);
	}

	/*
	 * (non-Javadoc)
	 * @see fr.asip.cps3.exemple.modele.jni.TraitementsSpecifiques#estInitialisee()
	 */
	public boolean estInitialisee() {
		return estChargee;
	}

	/*
	 * (non-Javadoc)
	 * @see fr.asip.cps3.exemple.modele.jni.TraitementsSpecifiques#getCodePorteur()
	 */
	public char[] getCodePorteur() {
		return codePorteur;
	}
	
	/*
	 * (non-Javadoc)
	 * @see fr.asip.cps3.exemple.modele.jni.TraitementsSpecifiques#setCodePorteur(char[])
	 */
	public void setCodePorteur(char[] codePorteur) {
		this.codePorteur = codePorteur;
	}

}
